#ifndef _XML_BIND_H
#define _XML_BIND_H

#include <string>
#include <vector>
#include "XmlDef.h"
using namespace std;
USING_XML_TOOL

#define XML_BIND_NAMESPACE				XmlBind
#define XML_BIND_NAMESPACE_BEGIN		namespace XML_BIND_NAMESPACE {
#define XML_BIND_NAMESPACE_END			}
#define USING_XML_BIND					using namespace XML_BIND_NAMESPACE;

XML_BIND_NAMESPACE_BEGIN

#ifdef WIN32
	#define THROW_DECLARE throw(...)
#else
	#ifdef _DEBUG
		#define THROW_DECLARE throw(string)
	#else
		#define THROW_DECLARE throw(int)
	#endif //_DEBUG
#endif //WIN32

enum XmlBindingType {
	AttrBinding = 0,
	IDAttrBinding,
	CompositeAttrBinding,
	IDCompositeAttrBinding,
	ChildNodeBinding,
	PolymorphicChildNodeBinding, 
	STLContainerBinding,
	STLPtrObjContainerBinding,
	STLContainerNodeBinding,
	STLPtrObjContainerNodeBinding,
	NodeBinding,
	PolymorphicNodeBinding,
};

template<class T>
class XmlBinding
{
public:
#ifndef ONLY_XML_PARSER
	virtual XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE = 0;
#endif // ONLY_XML_PARSER

	virtual void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE = 0;
	virtual XmlBindingType GetXmlBindingType() const = 0;
};

template<class T> 
class XmlTextBinding : public XmlBinding<T>
{
public:
#ifndef ONLY_XML_PARSER
	void BindToXmlText(string& xmlText, const T* objData, const string& encoding = "utf-8")
	{
		XmlNodePtr xmlNode = BindToXmlNode(NULL, objData);
		xmlText = xmlNode->GetDocument()->BindToXmlText(encoding);
		XmlFactory::GetXmlFactory()->ReleaseXmlDocument(xmlNode->GetDocument());
	}

#endif // ONLY_XML_PARSER

	void BindFromXmlText(const string& xmlText, T* objData, const string& encoding = "utf-8") const THROW_DECLARE
	{
		XmlDocumentPtr xmlDoc = XmlFactory::GetXmlFactory()->CreateXmlDocument(xmlText, encoding);
		XmlNodePtr xmlNode = xmlDoc->GetDocumentRoot();
		if(xmlNode == NULL)
		{
			XmlFactory::GetXmlFactory()->ReleaseXmlDocument(xmlDoc);
#ifdef _DEBUG
			throw string("invalid xml text");
#else
			throw 0;
#endif
		}

		try
		{
			BindFromXmlNode(xmlNode, objData);
		}
#ifdef WIN32
		catch (...)
		{
			XmlFactory::GetXmlFactory()->ReleaseXmlDocument(xmlDoc);
			throw 0;
		}
#else
#ifdef _DEBUG
		catch (string msg)
#else
		catch (int msg)
#endif //_DEBUG
		{
			XmlFactory::GetXmlFactory()->ReleaseXmlDocument(xmlDoc);
			throw msg;
		}
#endif //WIN32
		XmlFactory::GetXmlFactory()->ReleaseXmlDocument(xmlDoc);
	}
};

template<class T>
struct XmlBindingOption
{
	const string nodeName;
	const XmlBinding<T>* const* bindingInfo;
	const size_t bindingInfoSize;

	~XmlBindingOption()
	{
		for(size_t i = 0; i < bindingInfoSize; i++)
			delete bindingInfo[i];
	}
};

template<class T, class ParamType, class XmlNodeType, class ReturnType>
void VisiteBindingOption(const XmlBindingOption<T>* bindingOption, 
						 XmlNodeType xmlNode, 
						 ParamType objData,
						 ReturnType (XmlBinding<T>::*MemFunc)(XmlNodeType, ParamType, bool) const) THROW_DECLARE
{
	for(size_t i = 0; i < bindingOption->bindingInfoSize; i++)
	{
		const XmlBinding<T>* xmlBinding = bindingOption->bindingInfo[i];
		(xmlBinding->*MemFunc)(xmlNode, objData, false);
	}
}

template<class T, class MemberType>
class MemberTraits 
{
public:
	virtual MemberType* GetReference(const T* objData, bool createIfNotExist = true) = 0;
};

template<class T, class MemberType>
class PtrMemberTraits : public MemberTraits<T, MemberType>
{
public:
	PtrMemberTraits(MemberType* T::* memberPtr) 
		: mMemberPtr(memberPtr) {}

	virtual MemberType* GetReference(const T* objData, bool createIfNotExist = true) 
	{
		MemberType* memberObj = objData->*mMemberPtr;
		if(memberObj != NULL)
			return memberObj;
		if(createIfNotExist)
			(const_cast<T*>(objData))->*mMemberPtr = new MemberType;
		return objData->*mMemberPtr;
	}

protected:
	MemberType* T::* mMemberPtr;
};

template<class T, class ParentType, class SuperType>
class PolymorphicPtrMemberTraits : public PtrMemberTraits<T, ParentType>
{
public:
	PolymorphicPtrMemberTraits(ParentType* T::* memberPtr) 
		: PtrMemberTraits<T, ParentType>(memberPtr) {}

	virtual ParentType* GetReference(const T* objData, bool createIfNotExist = true) 
	{
		ParentType* memberObj = objData->*mMemberPtr;
		if(memberObj != NULL)
			return memberObj;
		if(createIfNotExist)
			(const_cast<T*>(objData))->*mMemberPtr = new SuperType;
		return objData->*mMemberPtr;
	}

	virtual void ReleaseObject(T* objData)
	{
		SuperType* superObj = static_cast<SuperType*>(objData->*mMemberPtr);
		if(superObj != NULL)
			delete superObj;
		objData->*mMemberPtr = NULL;
	}
};

template<class T, class MemberType>
class RefMemberTraits : public MemberTraits<T, MemberType>
{
public:
	RefMemberTraits(MemberType T::* memberPtr) 
		: mMemberPtr(memberPtr) {}

	virtual MemberType* GetReference(const T* objData, bool createIfNotExist = true) 
	{
		return &((const_cast<T*>(objData))->*mMemberPtr);
	}

private:
	MemberType T::* mMemberPtr;
};

template<class T, class MemberType>
class AttrObjXmlBinding : public XmlBinding<T>
{
public:
	AttrObjXmlBinding(const string& nodeName, MemberType T::* memberPtr, XmlBindingType bindingType = AttrBinding)
		: mNodeName(nodeName), mMemberPtr(memberPtr), mBindingType(bindingType) 
	{
	}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		xmlNode->SetAttribute(mNodeName, ConvertToString(objData->*mMemberPtr));
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		string attrValue;
		if(!xmlNode->GetAttribute(mNodeName, attrValue))
			return;
		ConvertFromString(attrValue, &(objData->*mMemberPtr));
	}

	XmlBindingType GetXmlBindingType() const { return mBindingType; }

protected:
	const string mNodeName;
	MemberType T::* mMemberPtr;
	XmlBindingType mBindingType;
};

template<class T, class StringType>
class AttrStringObjXmlBinding : public XmlBinding<T>
{
public:
	AttrStringObjXmlBinding(const string& attrName, StringType T::* memberPtr, 
							const string& encoding, const string& xmlEncoding = "utf-8")
		: mAttrName(attrName), mMemberPtr(memberPtr), mEncoding(encoding), mXmlEncoding(xmlEncoding)
	{
	}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		xmlNode->SetAttribute(mAttrName, ConvertToString(objData->*mMemberPtr, mEncoding, mXmlEncoding));
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		string attrValue;
		if(!xmlNode->GetAttribute(mAttrName, attrValue))
			return;
		ConvertFromString(attrValue, &(objData->*mMemberPtr), mXmlEncoding, mEncoding);
	}

	XmlBindingType GetXmlBindingType() const { return AttrBinding; }

private:
	const string mAttrName;
	const string mEncoding;
	const string mXmlEncoding;
	StringType T::* mMemberPtr;
};

template<class T, class MemberType, class BindingObjType = MemberType>
class CompositeAttrMemberXmlBinding : public XmlBinding<T>
{
public:
	CompositeAttrMemberXmlBinding(MemberTraits<T, MemberType>* memberTraits)
		: mMemberTraits(memberTraits) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		const MemberType* compositeObj = mMemberTraits->GetReference(objData, false);
		BindingObjType bindingType;
		const XmlBindingOption<MemberType>* bindingOption = bindingType.GetXmlBindingOption();
		VisiteBindingOption(bindingOption, xmlNode, compositeObj, &XmlBinding<MemberType>::BindToXmlNode);
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		MemberType* compositeObj = mMemberTraits->GetReference(objData, true);
		BindingObjType bindingType;
		const XmlBindingOption<MemberType>* bindingOption = bindingType.GetXmlBindingOption();
		VisiteBindingOption<MemberType, MemberType*, const XmlNodePtr, void>(bindingOption, xmlNode, compositeObj, &XmlBinding<MemberType>::BindFromXmlNode);
	}

	XmlBindingType GetXmlBindingType() const { return CompositeAttrBinding; }

protected:
	MemberTraits<T, MemberType>* mMemberTraits;
};

template<class T, class MemberType, class BindingObjType = MemberType>
class MemberIDAttrXmlBinding : public XmlBinding<T>
{
public:
	MemberIDAttrXmlBinding(MemberTraits<T, MemberType>* memberTraits)
		: mMemberTraits(memberTraits) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		const MemberType* compositeObj = mMemberTraits->GetReference(objData, false);
		const XmlBinding<MemberType>* xmlIDBinding = GetXmlIDBinding(objData);
		return xmlIDBinding->BindToXmlNode(xmlNode, compositeObj);
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		MemberType* compositeObj = mMemberTraits->GetReference(objData, true);
		const XmlBinding<MemberType>* xmlIDBinding = GetXmlIDBinding(objData);
		xmlIDBinding->BindFromXmlNode(xmlNode, compositeObj);
	}

	XmlBindingType GetXmlBindingType() const { return IDCompositeAttrBinding; }

private:
	const XmlBinding<MemberType>* GetXmlIDBinding(const T* objData) const THROW_DECLARE
	{
		BindingObjType bindingType;
		const XmlBindingOption<MemberType>* bindingOption = bindingType.GetXmlBindingOption();
		for(size_t i = 0; i < bindingOption->bindingInfoSize; i++)
		{
			if(bindingOption->bindingInfo[i]->GetXmlBindingType() == IDAttrBinding)
				return bindingOption->bindingInfo[i];
		}
		
#ifdef _DEBUG
		throw string("no id attribute binding");
#else
		throw 0;
#endif
	}

protected:
	MemberTraits<T, MemberType>* mMemberTraits;
};

template<class T, class MemberType, class BindingObjType = MemberType>
class MemberChildNodeXmlBinding : public XmlBinding<T>
{
public:
	MemberChildNodeXmlBinding(MemberTraits<T, MemberType>* memberTraits, const string& nodeName = "", bool nullable = false)
		: mMemberTraits(memberTraits), mNodeName(nodeName), mNullable(nullable) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		if(!parentNode)
#ifdef _DEBUG
			throw string("parent node can not be null");
#else
			throw 0;
#endif

		const MemberType* childObj = mMemberTraits->GetReference(objData, false);
		BindingObjType bindingType;
		const XmlBindingOption<MemberType>* bindingOption = bindingType.GetXmlBindingOption();
		XmlNodePtr childNode = parentNode->GetDocument()->CreateXmlNode(mNodeName.size() > 0 ? mNodeName: bindingOption->nodeName);
		parentNode->AppendChild(childNode);

		bindingType.BindToXmlNode(childNode, childObj, true);
		return childNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr parentNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		MemberType* childObj = mMemberTraits->GetReference(objData, true);
		BindingObjType bindingType;
		const XmlBindingOption<MemberType>* bindingOption = bindingType.GetXmlBindingOption();
		XmlNodePtr childNode = parentNode->GetFirstChild();
		while(childNode && childNode->GetNodeName() != (mNodeName.size() > 0 ? mNodeName: bindingOption->nodeName))
			childNode = childNode->GetNextSibling();

		if(childNode == NULL && !mNullable)
#ifdef _DEBUG
			throw string("no child node find for node name:") + bindingOption->nodeName;
#else
			throw 0;
#endif
		else if(childNode == NULL)
			return;

		bindingType.BindFromXmlNode(childNode, childObj, true);
	}

	XmlBindingType GetXmlBindingType() const { return ChildNodeBinding; }

private:
	MemberTraits<T, MemberType>* mMemberTraits;
	bool mNullable;
	string mNodeName;
};

template<class T, class ParentType, class SuperType, class SuperBinding, class DiscriminatorType>
class PolymorphicChildNodeXmlBinding : public XmlBinding<T>
{
public:
	PolymorphicChildNodeXmlBinding(PolymorphicPtrMemberTraits<T, ParentType, SuperType>* memberTraits,
									DiscriminatorType ParentType::* discriminatorMember,
									const DiscriminatorType discriminatorValue)
		: mMemberTraits(memberTraits), mDiscriminatorMember(discriminatorMember), mDiscriminatorValue(discriminatorValue) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		if(!parentNode)
#ifdef _DEBUG
			throw string("parent node can not be null");
#else
			throw 0;
#endif

		const ParentType* childObj = mMemberTraits->GetReference(objData, false);
		if(childObj->*mDiscriminatorMember != mDiscriminatorValue)
			return parentNode;

		SuperBinding bindingType;
		const XmlBindingOption<SuperType>* bindingOption = bindingType.GetXmlBindingOption();
		XmlNodePtr childNode = parentNode->GetDocument()->CreateXmlNode(bindingOption->nodeName);
		parentNode->AppendChild(childNode);

		const SuperType* superObj = static_cast<const SuperType*>(childObj);
		bindingType.BindToXmlNode(childNode, superObj, true);
		return childNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr parentNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		SuperBinding bindingType;
		const XmlBindingOption<SuperType>* bindingOption = bindingType.GetXmlBindingOption();
		XmlNodePtr childNode = parentNode->GetFirstChild();
		while(childNode && childNode->GetNodeName() != bindingOption->nodeName)
			childNode = childNode->GetNextSibling();

		if(childNode == NULL)
			return;

		SuperType* childObj = static_cast<SuperType*>(mMemberTraits->GetReference(objData, true));
		bindingType.BindFromXmlNode(childNode, childObj, true);
		if(childObj->*mDiscriminatorMember != mDiscriminatorValue)
			mMemberTraits->ReleaseObject(objData);
	}

	XmlBindingType GetXmlBindingType() const { return PolymorphicChildNodeBinding; }

private:
	PolymorphicPtrMemberTraits<T, ParentType, SuperType>* mMemberTraits;
	DiscriminatorType ParentType::* mDiscriminatorMember;
	const DiscriminatorType mDiscriminatorValue;
};


template<class T, class BindingObjType = T>
class ObjectNodeXmlBinding : public virtual XmlTextBinding<T>
{
public:
#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		BindingObjType bindingType;
		const XmlBindingOption<T>* bindingOption = bindingType.GetXmlBindingOption();

		XmlNodePtr xmlNode = parentNode;
		if(!noCheck)
		{
			XmlDocumentPtr xmlDoc = NULL;
			if(parentNode == NULL)
				xmlDoc = XmlFactory::GetXmlFactory()->CreateXmlDocument();
			else
				xmlDoc = parentNode->GetDocument();

			xmlNode = xmlDoc->CreateXmlNode(bindingOption->nodeName);
			if(parentNode)
				parentNode->AppendChild(xmlNode);
			else
				xmlDoc->SetDocumentRoot(xmlNode);
		}
		
		VisiteBindingOption(bindingOption, xmlNode, objData, &XmlBinding<T>::BindToXmlNode);
		return xmlNode;
	}

#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		BindingObjType bindingType;
		const XmlBindingOption<T>* bindingOption = bindingType.GetXmlBindingOption();

		if(!noCheck && xmlNode->GetNodeName() != bindingOption->nodeName)
#ifdef _DEBUG
			throw string("no node find for node name:") + bindingOption->nodeName;
#else
			throw 0;
#endif

		VisiteBindingOption<T, T*, const XmlNodePtr, void>(bindingOption, xmlNode, objData, &XmlBinding<T>::BindFromXmlNode);
	}

	XmlBindingType GetXmlBindingType() const { return NodeBinding; }

protected:
	bool mInherited;
};

template<class T, template<class, class> class ContainerType>
class StlContainerXmlBinding : public virtual XmlTextBinding<ContainerType<T, allocator<T> > >
{
public:
	typedef ContainerType<T, allocator<T> > StlContainer;

	StlContainerXmlBinding(const string& rootName, const string& nodeName) 
		: mRootName(rootName), mNodeName(nodeName){}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		XmlDocumentPtr xmlDoc = NULL;
		if(parentNode == NULL)
			xmlDoc = XmlFactory::GetXmlFactory()->CreateXmlDocument();
		else
			xmlDoc = parentNode->GetDocument();

		XmlNodePtr xmlNode = xmlDoc->CreateXmlNode(mRootName);
		if(parentNode)
			parentNode->AppendChild(xmlNode);
		else
			xmlDoc->SetDocumentRoot(xmlNode);

		typename StlContainer::const_iterator iter = containerObj->begin();
		for(; iter != containerObj->end(); iter++)
		{
			string szValue = ConvertToString(*iter);
			xmlNode->AppendChild(xmlDoc->CreateTextNode(mNodeName, szValue));
		}
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		if(xmlNode->GetNodeName() != mRootName)
#ifdef _DEBUG
			throw string("no node find for node name:") + mNodeName;
#else
			throw 0;
#endif

		XmlNodePtr childNode = xmlNode->GetFirstChild();
		while(childNode)
		{
			if(childNode->GetNodeName() == mNodeName)
			{
				string text = childNode->GetTextContent();
				if(text == "")
					continue;
				T dataObj;
				ConvertFromString(text, &dataObj);
				containerObj->push_back(dataObj);
			}
			childNode = childNode->GetNextSibling();
		}
	}

	XmlBindingType GetXmlBindingType() const { return STLContainerBinding; }

	const string mRootName;
	const string mNodeName;
};

template<class T = string, template<class, class> class ContainerType>
class StlStringContainerXmlBinding : public virtual XmlTextBinding<ContainerType<T, allocator<T> > >
{
public:
	typedef ContainerType<T, allocator<T> > StlContainer;

	StlStringContainerXmlBinding(const string& rootName, const string& nodeName, 
								const string& encoding, const string& xmlEncoding = "utf-8") 
		: mRootName(rootName), mNodeName(nodeName), mEncoding(encoding), mXmlEncoding(xmlEncoding) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		XmlDocumentPtr xmlDoc = NULL;
		if(parentNode == NULL)
			xmlDoc = XmlFactory::GetXmlFactory()->CreateXmlDocument();
		else
			xmlDoc = parentNode->GetDocument();

		XmlNodePtr xmlNode = xmlDoc->CreateXmlNode(mRootName);
		if(parentNode)
			parentNode->AppendChild(xmlNode);
		else
			xmlDoc->SetDocumentRoot(xmlNode);

		typename StlContainer::const_iterator iter = containerObj->begin();
		for(; iter != containerObj->end(); iter++)
		{
			string szValue = ConvertToString(*iter, mEncoding, mXmlEncoding);
			xmlNode->AppendChild(xmlDoc->CreateTextNode(mNodeName, szValue));
		}
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		if(xmlNode->GetNodeName() != mRootName)
#ifdef _DEBUG
			throw string("no node find for node name:") + mNodeName;
#else
			throw 0;
#endif

		XmlNodePtr childNode = xmlNode->GetFirstChild();
		while(childNode)
		{
			if(childNode->GetNodeName() == mNodeName)
			{
				string text = childNode->GetTextContent();
				if(text == "")
					continue;
				T dataObj;
				ConvertFromString(text, &dataObj, mXmlEncoding, mEncoding);
				containerObj->push_back(dataObj);
			}
			childNode = childNode->GetNextSibling();
		}
	}

	XmlBindingType GetXmlBindingType() const { return STLContainerBinding; }

private:
	const string mRootName;
	const string mNodeName;
	const string mEncoding;
	const string mXmlEncoding;
};

template<class T, template<class, class> class ContainerType, class BindingObjType>
class StlPtrObjContainerXmlBinding : public XmlTextBinding<ContainerType<T*, allocator<T*> > >
{
public:
	typedef ContainerType<T*, allocator<T*> > StlContainer;

	StlPtrObjContainerXmlBinding(const string& nodeName) 
		: mNodeName(nodeName) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		XmlDocumentPtr xmlDoc = NULL;
		if(parentNode == NULL)
			xmlDoc = XmlFactory::GetXmlFactory()->CreateXmlDocument();
		else
			xmlDoc = parentNode->GetDocument();

		XmlNodePtr xmlNode = NULL;
		if(mNodeName.size() > 0)
		{
			xmlNode = xmlDoc->CreateXmlNode(mNodeName);
			if(parentNode)
				parentNode->AppendChild(xmlNode);
			else
				xmlDoc->SetDocumentRoot(xmlNode);
		}
		else
			xmlNode = parentNode;

		typename StlContainer::const_iterator iter = containerObj->begin();
		BindingObjType bindingType;
		const XmlBindingOption<T>* bindingOption = bindingType.GetXmlBindingOption();
		for(; iter != containerObj->end(); iter++)
		{
			const T* objData = *iter;
			bindingType.BindToXmlNode(xmlNode, objData);
		}
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		if(mNodeName.size() > 0 && xmlNode->GetNodeName() != mNodeName)
#ifdef _DEBUG
			throw string("no node find for node name:") + mNodeName;
#else
			throw 0;
#endif

		BindingObjType bindingType;
		const XmlBindingOption<T>* bindingOption = bindingType.GetXmlBindingOption();
		XmlNodePtr childNode = NULL;
		if(mNodeName.size() > 0)
			childNode = xmlNode->GetFirstChild();
		else
			childNode = xmlNode;
		while(childNode)
		{
			if(childNode->GetNodeName() == bindingOption->nodeName)
			{
				T* obj = new T;
				bindingType.BindFromXmlNode(childNode, obj);
				containerObj->push_back(obj);
			}
			childNode = childNode->GetNextSibling();
		}
	}

	XmlBindingType GetXmlBindingType() const { return STLPtrObjContainerBinding; }

	const string mNodeName;
};

template<class T, template<class, class> class ContainerType, class BindingObjType>
class StlRefObjContainerXmlBinding : public XmlTextBinding<ContainerType<T, allocator<T> > >
{
public:
	typedef ContainerType<T, allocator<T> > StlContainer;

	StlRefObjContainerXmlBinding(const string& nodeName) 
		: mNodeName(nodeName) {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		XmlDocumentPtr xmlDoc = NULL;
		if(parentNode == NULL)
			xmlDoc = XmlFactory::GetXmlFactory()->CreateXmlDocument();
		else
			xmlDoc = parentNode->GetDocument();

		XmlNodePtr xmlNode = NULL;
		if(mNodeName.size() > 0)
		{
			xmlNode = xmlDoc->CreateXmlNode(mNodeName);
			if(parentNode)
				parentNode->AppendChild(xmlNode);
			else
				xmlDoc->SetDocumentRoot(xmlNode);
		}
		else
			xmlNode = parentNode;

		typename StlContainer::const_iterator iter = containerObj->begin();
		BindingObjType bindingType;
		const XmlBindingOption<T>* bindingOption = bindingType.GetXmlBindingOption();
		for(; iter != containerObj->end(); iter++)
		{
			const T& objData = *iter;
			bindingType.BindToXmlNode(xmlNode, &objData);
		}
		return xmlNode;
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, StlContainer* containerObj, bool noCheck = false) const THROW_DECLARE
	{
		if(mNodeName.size() > 0 && xmlNode->GetNodeName() != mNodeName)
#ifdef _DEBUG
			throw string("no node find for node name:") + mNodeName;
#else
			throw 0;
#endif

		BindingObjType bindingType;
		const XmlBindingOption<T>* bindingOption = bindingType.GetXmlBindingOption();
		XmlNodePtr childNode = NULL;
		if(mNodeName.size() > 0)
			childNode = xmlNode->GetFirstChild();
		else
			childNode = xmlNode;
		while(childNode)
		{
			if(childNode->GetNodeName() == bindingOption->nodeName)
			{
				T obj;
				bindingType.BindFromXmlNode(childNode, &obj);
				containerObj->push_back(obj);
			}
			childNode = childNode->GetNextSibling();
		}
	}

	XmlBindingType GetXmlBindingType() const { return STLPtrObjContainerBinding; }

	const string mNodeName;
};

template<class T, class MemberType, template<class, class> class ContainerType>
class StlContainerChildNodeXmlBinding : public XmlBinding<T>
{
public:
	typedef ContainerType<MemberType, allocator<MemberType> > StlContainer;

	StlContainerChildNodeXmlBinding(const string& rootName, const string& nodeName, MemberTraits<T, StlContainer>* memberTraits)
		: mContainerBinding(rootName, nodeName), mMemberTraits(memberTraits)
	{
	}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		const StlContainer* containerObj = mMemberTraits->GetReference(objData, false);
		return mContainerBinding.BindToXmlNode(xmlNode, containerObj);
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		XmlNodePtr childNode = xmlNode->GetFirstChild();
		while(childNode && childNode->GetNodeName() != mContainerBinding.mRootName)
			childNode = childNode->GetNextSibling();

		if(childNode == NULL)
#ifdef _DEBUG
			throw string("no node find for node name:") + mContainerBinding.mRootName;
#else
			throw 0;
#endif

		StlContainer* containerObj = mMemberTraits->GetReference(objData, true);
		mContainerBinding.BindFromXmlNode(childNode, containerObj);
	}

	XmlBindingType GetXmlBindingType() const { return STLContainerNodeBinding; }

protected:
	StlContainerXmlBinding<MemberType, ContainerType> mContainerBinding;
	MemberTraits<T, StlContainer>* mMemberTraits;
};

template<class T, class MemberType, template<class, class> class ContainerType, class BindingObjType>
class StlPtrObjContainerChildNodeXmlBinding : public XmlBinding<T>
{
public:
	typedef ContainerType<MemberType*, allocator<MemberType*> > StlContainer;

	StlPtrObjContainerChildNodeXmlBinding(const string& nodeName, MemberTraits<T, StlContainer>* memberTraits)
		: mContainerBinding(nodeName), mMemberTraits(memberTraits)
	{
	}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		const StlContainer* containerObj = mMemberTraits->GetReference(objData, false);
		return mContainerBinding.BindToXmlNode(xmlNode, containerObj);
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		XmlNodePtr childNode = xmlNode->GetFirstChild();
		if(mContainerBinding.mNodeName.size() > 0)
		{
			while(childNode && childNode->GetNodeName() != mContainerBinding.mNodeName)
				childNode = childNode->GetNextSibling();
		}

//		if(childNode == NULL)
//#ifdef _DEBUG
//			throw string("no node find for node name:") + mContainerBinding.mNodeName;
//#else
//			throw 0;
//#endif
		StlContainer* containerObj = mMemberTraits->GetReference(objData, true);
		mContainerBinding.BindFromXmlNode(childNode, containerObj);
	}

	XmlBindingType GetXmlBindingType() const { return STLContainerNodeBinding; }

protected:
	StlPtrObjContainerXmlBinding<MemberType, ContainerType, BindingObjType> mContainerBinding;
	MemberTraits<T, StlContainer>* mMemberTraits;
};

template<class T, class MemberType, template<class, class> class ContainerType, class BindingObjType>
class StlRefObjContainerChildNodeXmlBinding : public XmlBinding<T>
{
public:
	typedef ContainerType<MemberType, allocator<MemberType> > StlContainer;

	StlRefObjContainerChildNodeXmlBinding(const string& nodeName, MemberTraits<T, StlContainer>* memberTraits)
		: mContainerBinding(nodeName), mMemberTraits(memberTraits)
	{
	}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr xmlNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		const StlContainer* containerObj = mMemberTraits->GetReference(objData, false);
		return mContainerBinding.BindToXmlNode(xmlNode, containerObj);
	}
#endif // ONLY_XML_PARSER

	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		XmlNodePtr childNode = xmlNode->GetFirstChild();
		if(mContainerBinding.mNodeName.size() > 0)
		{
			while(childNode && childNode->GetNodeName() != mContainerBinding.mNodeName)
				childNode = childNode->GetNextSibling();
		}
		
		if(childNode == NULL)
#ifdef _DEBUG
			throw string("no node find for node name:") + mContainerBinding.mNodeName;
#else
			throw 0;
#endif
		StlContainer* containerObj = mMemberTraits->GetReference(objData, true);
		mContainerBinding.BindFromXmlNode(childNode, containerObj);
	}

	XmlBindingType GetXmlBindingType() const { return STLContainerNodeBinding; }

protected:
	StlRefObjContainerXmlBinding<MemberType, ContainerType, BindingObjType> mContainerBinding;
	MemberTraits<T, StlContainer>* mMemberTraits;
};

template<class T, class BindingObjType = T>
class AbstractObjectXmlBinding : public virtual ObjectNodeXmlBinding<T, BindingObjType>
{
public:
	virtual ~AbstractObjectXmlBinding() {}
	virtual const XmlBindingOption<T>* GetXmlBindingOption() const = 0;
};

template<class T, class BindingObjType, class ParentType, class ParentBindingObjType>
class AbstractPolymorphicObjectXmlBinding : public virtual AbstractObjectXmlBinding<T, BindingObjType>
{
public:
	virtual ~AbstractPolymorphicObjectXmlBinding() {}

#ifndef ONLY_XML_PARSER
	XmlNodePtr BindToXmlNode(XmlNodePtr parentNode, const T* objData, bool noCheck = false) const THROW_DECLARE
	{
		XmlNodePtr xmlNode = ObjectNodeXmlBinding<T, BindingObjType>::BindToXmlNode(parentNode, objData, noCheck);

		ParentBindingObjType parentBinding;
		parentBinding.BindToXmlNode(xmlNode, dynamic_cast<const ParentType*>(objData), true);
		return xmlNode; 
	}
#endif // ONLY_XML_PARSER
	
	void BindFromXmlNode(const XmlNodePtr xmlNode, T* objData, bool noCheck = false) const THROW_DECLARE
	{
		ObjectNodeXmlBinding<T, BindingObjType>::BindFromXmlNode(xmlNode, objData, noCheck);

		ParentBindingObjType parentBinding;
		parentBinding.BindFromXmlNode(xmlNode, dynamic_cast<ParentType*>(objData), true);
	}

	XmlBindingType GetXmlBindingType() const { return PolymorphicNodeBinding; }

};

XML_BIND_NAMESPACE_END

#include "Converter.h"

#endif //_XML_BIND_H
